#include <iostream>
#include <string.h>
using namespace std;
class CowString{
public:
    CowString()
        //数据前面分配四个字节用来存储引用计数
        //指针+4偏移到数据的位置
        :_pstr(new char[5]()+4)
    {
        cout << "cowString()"<<endl;
        *(int *)(_pstr -4) = 1;
    }
    //拷贝构造函数
    //主要作用是将C风格的字符串转换成CowString类型
    CowString(const char * pstr)
        :_pstr(new char[strlen(pstr) +5]+4)
    {
        cout<<"CowString(const char *)"<<endl;
        strcpy(_pstr,pstr);
        *(int *)(_pstr -4) = 1;
    }
    //浅拷贝
    //增加引用计数
    CowString(const CowString & rhs)
        :_pstr(rhs._pstr)
    {
        cout<<"CowString(const CowString &)"<<endl;
        ++*(int *)(_pstr -4);
    }
    //赋值运算函数
    CowString & operator=(const CowString & rhs){
        cout<<"CowString & operator=(const CowString &)"<<endl;
        //不是自赋值，如果是字符值就没必要改动引用计数
        if(this != &rhs){
            if(--*(int *)(_pstr -4) == 0){
                //如果引用计数为0了就要销毁释放
                delete  [] (_pstr -4);
            }
            //将指针指向新的赋值内存
            _pstr = rhs._pstr;
            ++*(int *)(_pstr -4);
        }
        return *this;
    }
    ~CowString(){
        cout<<"~CowString()"<<endl;
        if(--*(int *)(_pstr -4) == 0){
            delete  [](_pstr -4);
        }
    }
    const char * c_str()const{
        return _pstr;
    }

    friend ostream & operator <<(ostream &os,CowString & rhs);
    //重载[]运算符
    char & operator[](size_t index){
        if(index <= size()){
            //修改，如果引用计数 > 1,需要复制空间
            if(*(int *)(_pstr -4)>1){
              char * temp = new char[size() + 5]() +4;
              strcpy(temp,_pstr);
              //原来的引用计数 -1
              --*(int *)(_pstr -4);
              //现在的引用计数=1
              _pstr = temp;
              *(int *)(_pstr -4) = 1;
            }
            return _pstr[index];
        }else{
            static char nullchar = '\0';
            return nullchar;
        }
    }
    size_t refcount()const{
        return *(int *)(_pstr -4);
    }
    size_t size() const{
        return strlen(_pstr);
    }

private:
    char * _pstr;

};
ostream & operator<<(ostream & os,CowString & rhs){
    if(rhs._pstr){
        os<<rhs._pstr;
    }
    return os;
}

void test(){
    CowString s1("Hello World");
    CowString s2;
    CowString s3 = s1;
    cout << s1[0]<<endl;
    s1[0] = 'h';
    cout<<s3[0]<<endl;
    s2 = s1;
    s1[0] = 'h';
    cout<< s1<<endl;
    cout << s2<<endl;
}
int main()
{
    test();
    return 0;
}

